#include "PlayerController.h"
#include "Pathing.h"

#define PATH_RECURSION_DEPTH 6

const HashedString PlayerController::type("PlayerController");

PlayerController::PlayerController( Entity* entity ) : IEntityController(entity)
{
	m_orientation = (OrientationComponent*)(m_entity->FindComponent(OrientationComponent::type));
	m_rigidbody = (RigidBodyComponent*)(m_entity->FindComponent(RigidBodyComponent::type));
	m_status = (StatusComponent*)(m_entity->FindComponent(StatusComponent::type));
	m_combat = (CombatComponent*)(m_entity->FindComponent(CombatComponent::type));
	LinkPosition(m_orientation->getPosition());
}

void PlayerController::LinkPosition( Subject<Maths::Vector3D>& position )
{
	m_position = new DoubleValueTrigger<Maths::Vector3D>(&position, &m_vehicle.getPosition());
}

void PlayerController::UpdateVelocity( Maths::Vector3D& velocity )
{
	if (m_rigidbody)
	{
		m_rigidbody->getBody()->getRigidBody()->setLinearVelocity(btVector3(velocity.X(), velocity.Y(), velocity.Z()));
		m_rigidbody->getBody()->getRigidBody()->activate();
	}
}

void PlayerController::UpdateStatus( HashedString status, int value )
{
	if (m_status)
	{
		StatusComponent::Status& stat = m_status->getStatus(status);
		stat = value;
	}
}

void PlayerController::getPosition( Maths::Vector3D& position )
{
	position = m_orientation->getPosition().getObject();
}

void PlayerController::getStatus( HashedString status, int& value )
{
	if (m_status)
	{
		StatusComponent::Status& stat = m_status->getStatus(status);
		value = stat.getObject();
	}
}

Pathing::Vehicle& PlayerController::Vehicle()
{
	return m_vehicle;
}

void PlayerController::getDirection( Maths::Vector3D& direction )
{
	m_vehicle.Direction(direction);
}

void PlayerController::Update()
{
	m_player->Update();
}

void PlayerController::UpdatePath()
{
	float costOfPath;
	if (m_world.isValid())
	{
		m_vehicle.Path().clear();
		Pathing::GetPathofVehicleToDestination(m_vehicle, m_world->Obstacles(), costOfPath, m_vehicle.Path(), PATH_RECURSION_DEPTH);
		if (m_vehicle.Path().size() == 0 && m_vehicle.Position().Distance(Maths::Vector3D(m_vehicle.Destination())) < Maths::EPSILON)
			m_vehicle.Sleeping() = true;
	}
}

void PlayerController::UpdateDirectionNode()
{
	if (m_world.isValid())
		if (LOSVehicleNextNode( m_vehicle, m_world->Obstacles() ))				// Can AI see the next node?
			m_vehicle.PopPathingPoint();							// Move towards it if so
}

void PlayerController::UpdateDestination( Maths::Vector3D& destination )
{
	m_vehicle.Destination(destination);
}

void PlayerController::setWorld( Pointer<Pathing::World>& world )
{
	m_world = world;
}

const HashedString& PlayerController::Type()
{
	return type;
}

std::list<Maths::Vector3D>& PlayerController::getWaypoints()
{
	return m_waypoints;
}

void PlayerController::setPlayer( Pointer<Player> behavior )
{
	m_player = behavior;
}

Pointer<Player> PlayerController::getPlayer( )
{
	return m_player;
}

void PlayerController::ToXML( tinyxml2::XMLPrinter& printer )
{
	/*
	printer.OpenElement("Player");
	printer.PushAttribute("Type", m_player->Type().getString().c_str());

	m_behavior->ToXML(printer);

	printer.CloseElement();	

	for (std::list<Maths::Vector3D>::iterator it = m_waypoints.begin(); it != m_waypoints.end(); ++it)
	{
		printer.OpenElement("Waypoint");
		
		char buffer[50];
		sprintf_s(buffer, 50, "%.3f %.3f %.3f", it->X(), it->Y(), it->Z());

		printer.PushAttribute("Vector", buffer);

		printer.CloseElement();
	}
	*/
}


Combat::IAbility::Vector_t& PlayerController::getAbilities()
{
	return m_combat->Combatant()->Abilities();
}